#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>
#include <errno.h>
#include "simpletimer.h"

/* simpletimer.c. Define a função init_timer declarada em simpletimer.h
 * Programa um alarme periodico com um intervalo igual ao valor do
 * parametro dado em milésimos de segundos. Para isso instala primeiramente
 * uma funcao fornecida pelo usuário para tratar o sinal SIGALRM gerado
 * pelo temporizador do sistema.
 */

/* Primeiramente, init_timer() registra o tratador junto
 * ao sistema operacional. Isso e' feito criando uma struct sigaction
 * para descrever o tratador do sinal SIGALRM como sendo a funcao tictac
 * e utilizando a funcao sigaction para registrar o tratador no sistema
 * operacional. 
 * OBS.: outra forma de fazer isso seria com o uso da funcao signal(),
 * mais simples, mas cujo uso e' hoje desaconselhado.
 *
 * Depois de criar o tratador, init_timer() programa o temporizador.
 * O temporizador e' programado utilizando-se a funcao setitimer, que
 * recebe como parametro uma struct itimerval que permite definir um tempo
 * para a primeira ocorrencia do alarme e um intervalo para ser reutilizado
 * a partir de entao. No caso em questao, os dois sao iguais, garantindo
 * que todas as ocorrencias serao espacadas do mesmo tempo. Os timers tem
 * uma precisao maior que simples segundos, podendo os intervalos ser
 * especificados em termos de micro-segundos. Entretanto, a resolucao real
 * do temporizador normalmente e' maior isso, nao sendo aconselhavel 
 * confiar-se em temporizacoes menores que dezenas de mili-segundos.
 * Neste caso nao precisamos nos preocupar, pois usaremos apenas segundos.
 */

void
init_timer( timer_func_t tictac, int ms )
{
  struct sigaction act;
  sigset_t         set;
  struct itimerval itv;

  sigemptyset(&set);
  act.sa_handler = tictac;
  act.sa_mask    = set;
  act.sa_flags   = 0;
  
  sigaction(SIGALRM, &act, NULL);

  /* Não se esquecer que tv_usec é em MICROsegundos, mas a função que
   * definimos tem resolução de MILIsegundos
   */
  itv.it_interval.tv_sec  =  ms / 1000;
  itv.it_interval.tv_usec = (ms % 1000)*1000; 
  itv.it_value.tv_sec     =  ms / 1000;
  itv.it_value.tv_usec    = (ms % 1000)*1000;

  setitimer(ITIMER_REAL, &itv, NULL);
}
